home *** CD-ROM | disk | FTP | other *** search
/ PC Graphics Unleashed / PC Graphics Unleashed.iso / ch03 / io.c < prev    next >
C/C++ Source or Header  |  1993-05-21  |  26KB  |  991 lines

  1. /****************************************************************
  2. * FILE:    io.c
  3. * DESC:    These are the basic input/output routines. They include
  4. *        disk-handling and keyboard I/O.
  5. * HISTORY:    Created      3/11/1993
  6. * LAST CHANGED: 5/ 6/1993
  7. *    Copyright (c) 1993 by Scott Anderson
  8. *
  9. ****************************************************************/
  10.  
  11. /* ----------------------INCLUDES----------------------------- */
  12.  
  13. #include <conio.h>
  14. #include <stdio.h>
  15. #include <io.h>
  16. #include <dos.h>            /* for the mouse */
  17. #include <math.h>
  18. #include <graph.h>
  19. #include <malloc.h>
  20. #include <memory.h>
  21. #include <string.h>
  22.  
  23. #include "define.h"
  24.  
  25. /* ----------------------DEFINES------------------------------ */
  26.  
  27. /* 0-99 (for tweens) appended to name */
  28. #define MAX_NAME_SIZE    (8-2)    
  29.  
  30. /**** PCX constants ****/
  31. /* Set top 2 bits for the count bytes */
  32. #define C0                (0xc0)
  33. /* The inverse of C0: 0x3f = 63 */
  34. #define MAX_RUN            (0x3f)
  35. /* Signals a 256 color palette */
  36. #define PAL_CODE        12        
  37.  
  38. /* -----------------------MACROS------------------------------ */
  39.  
  40. /* ----------------------TYPEDEFS----------------------------- */
  41.  
  42. typedef struct {
  43.     char manufacturer;
  44.     char version;
  45.     char encoding;
  46.     char bperpixelperplane;
  47.     unsigned int xmin, ymin, xmax, ymax;
  48.     unsigned int hres, vres;
  49.     char rgbmap[3][16];
  50.     char reserved;
  51.     char nplanes;
  52.     unsigned int bytesperline;
  53.     unsigned int paletteinfo;
  54. }
  55. CORE_PCX_HEADER;
  56.  
  57. typedef struct {
  58.     CORE_PCX_HEADER pcx;
  59.     unsigned char filler[128-sizeof (CORE_PCX_HEADER)];
  60. }
  61. HEADER_PCX;
  62.  
  63. /* ----------------------PROTOTYPES--------------------------- */
  64.  
  65. char        lineAsk(char *name);
  66. void        setTextMode();
  67. void        setGraphicsMode();
  68. int            fixFilename(char *userName, char *fixedName,
  69.                             char *extension, int number);
  70. LINE_LIST    *loadLines(char *filename, char *extension);
  71. int            saveLines(char *filename, LINE_LIST *lineList,
  72.                             char *extension);
  73. LINKED_LIST    *appendName(LINKED_LIST *head, char *name);
  74. LINKED_LIST    *rootSequence(int argc, char *argv[]);
  75. int            waitForKey();
  76.  
  77. /* ----------------------GLOBAL DATA-------------------------- */
  78.  
  79. int     CurrentPal = 0;    /* ID of current palette */
  80.  
  81. int        Wait = 0;
  82. int     Key;
  83. int        EndWait = OFF;
  84.  
  85. /* from the last read file, used to save pic */
  86. static HEADER_PCX     Header;
  87.  
  88. /* Global values set from last picture loaded */
  89. int Xmin, Ymin, Xmax, Ymax;
  90.  
  91. /* no file output for NULL name */
  92. char    *OutFilename = NULL;
  93. long    TotalBytes;
  94.  
  95. int     Button;
  96. int        Keystroke;
  97.  
  98. /***************   The file handling routines   *****************/
  99.  
  100. /*****************************************************************
  101. * FUNC: int    saveScreen(PALETTE *pal)
  102. * DESC: Save the current screen with the given palette
  103. *****************************************************************/
  104.  
  105. int
  106. saveScreen(PALETTE *pal)
  107. {
  108.     static int        fileCount = 0;
  109.  
  110.     unsigned int    byteCount = 0;
  111.     unsigned char    lastColor;
  112.     unsigned char    color;
  113.     /* The number of bytes in a run */
  114.     unsigned char    num;
  115.  
  116.     int        index;
  117.     int        x, y;
  118.     /* big enough for number & '.PCX' */
  119.     char     pcxName[MAX_PATHLEN];
  120.     FILE     *fp;
  121.     char    *p;
  122.  
  123.     if (!OutFilename)    /* no file name on command line */
  124.         return 0;
  125.  
  126.     /* Create a numbered file name for output */
  127.     fileCount++;
  128.     fixFilename(OutFilename, pcxName, EXT_PCX, fileCount);
  129.  
  130.     /* Open the file and print the PCX file header */
  131.     if ((fp = fopen (pcxName, "wb")) == NULL)
  132.         quit (WRITE_OPEN_ERR, pcxName);
  133.     byteCount = fwrite (&Header, 1, sizeof (Header), fp);
  134.     if (byteCount != sizeof (Header))
  135.         quit (WRITE_ERR, pcxName);
  136.  
  137.     /* pack the the screen lines before writing them */
  138.     for (y = Ymin; y <= Ymax; y++) {
  139.         num = 1;        /* prime algorithm with the 1st pixel */
  140.         lastColor = _getpixel (Xmin, y);
  141.         for (x = Xmin + 1; x <= Xmax; x++) {
  142.             color = _getpixel (x, y);
  143.             if (color == lastColor) {
  144.                 num++;        /* Accumulate same-colored pixels */
  145.                 if (num == MAX_RUN) {
  146.                     byteCount += putBlock (num, lastColor, fp);
  147.                     num = 0;
  148.                 }
  149.             }
  150.             else {    /* This is a pixel of a different color */
  151.                 if (num) 
  152.                     byteCount += putBlock (num, lastColor, fp);
  153.                 lastColor = color;
  154.                 num = 1;
  155.             }
  156.         }
  157.         /* flush the last byte or batch of bytes on a line */
  158.         if (num)
  159.             byteCount += putBlock (num, lastColor, fp);
  160.     }
  161.     /* Finally, the color palette */
  162.     num = PAL_CODE;        /* Write out the palette code byte */
  163.     byteCount += writeByte (&num, fp);
  164.  
  165.     /* Write the color palette */
  166.     for (index = 0; index < COLORS;  index++) {
  167.         color = pal->c[index].r << 3;
  168.         byteCount += writeByte (&color, fp);
  169.         color = pal->c[index].g << 3;
  170.         byteCount += writeByte (&color, fp);
  171.         color = pal->c[index].b << 3;
  172.         byteCount += writeByte (&color, fp);
  173.     }
  174.     fclose (fp);
  175.     return byteCount;
  176. }
  177.  
  178. /*****************************************************************
  179. * FUNC: int    putBlock(unsigned char num, unsigned char color,
  180. *                                                    FILE *fp)
  181. * DESC: Write out the 2 or 1 byte block for Run Length Encoding.
  182. *****************************************************************/
  183.  
  184. int
  185. putBlock(unsigned char num, unsigned char color, FILE *fp)
  186. {
  187.     unsigned int byteCount = 0;
  188.  
  189.     /* Singlet colors with the top 2 bits set could be
  190.         confused with a count, so first write the one-count. */
  191.     if ((num > 1) || ((num == 1) && ((color & C0) == C0))) {
  192.         num |= C0;
  193.         byteCount += writeByte (&num, fp);
  194.     }
  195.     byteCount += writeByte (&color, fp);
  196.     return byteCount;
  197. }
  198.  
  199. /*****************************************************************
  200. * FUNC: int    writeByte(unsigned char *byte, FILE *fp)
  201. * DESC: Write one byte to the file and quit if there is an error.
  202. *****************************************************************/
  203.  
  204. int
  205. writeByte(unsigned char *byte, FILE *fp)
  206. {
  207.     int count;
  208.  
  209.     count = fwrite (byte, sizeof (char), 1, fp);
  210.     if (count != 1)
  211.         quit (WRITE_ERR, "");
  212.     return count;
  213. }
  214.  
  215. /*****************************************************************
  216. * FUNC: loadPicture (char *filename)
  217. * DESC: Read a PCX file from the disk into a buffer
  218. *****************************************************************/
  219.  
  220. PICTURE *loadPicture (char *filename)
  221. {
  222.     char         pcxName[MAX_PATHLEN];
  223.     FILE         *fp;
  224.     int            num, count;
  225.     PICTURE     *picture;
  226.     unsigned int        bytes_read;
  227.     unsigned char        byte;
  228.     unsigned char far     *bufptr;
  229.  
  230.     fixFilename(filename, pcxName, EXT_PCX, 0);
  231.  
  232.     fp = fopen(pcxName, "rb");
  233.     if (fp == NULL)
  234.         quit (READ_OPEN_ERR, pcxName);
  235.     picture = malloc(sizeof (*picture));
  236.     mustRead(fp, (char *) &Header, sizeof Header);
  237.  
  238.     Xmin = picture->xmin = Header.pcx.xmin;
  239.     Ymin = picture->ymin = Header.pcx.ymin;
  240.     Xmax = picture->xmax = Header.pcx.xmax;
  241.     Ymax = picture->ymax = Header.pcx.ymax;
  242.     picture->tall = Ymax - Ymin + 1;
  243.     picture->wide = Xmax - Xmin + 1;
  244.     picture->pal_id = 0;
  245.     if (picture->tall != MAX_TALL
  246.             || picture->wide != MAX_WIDE
  247.             || Header.pcx.bperpixelperplane != 8
  248.             || Header.pcx.nplanes != 1)
  249.         quit (WRONG_PCX_FILE, pcxName);
  250.     TotalBytes = picture->tall * (long) picture->wide;
  251.     TotalBytes = MIN(TotalBytes, MAX_BYTES);
  252.  
  253.     picture->pixmap = (unsigned char far *)
  254.                         _fmalloc((size_t) TotalBytes);
  255.     if (picture->pixmap == NULL)
  256.         return(NULL);
  257.     bufptr = picture->pixmap;
  258.     bytes_read = 0;
  259.  
  260.     while (getBlock(&byte, &count, fp) != EOF) {
  261.         if ((bytes_read += count) > TotalBytes)
  262.             break;
  263.         for (num = 0; num < count; num++)
  264.             *bufptr++ = byte;
  265.     }
  266.     if (Header.pcx.version == 5)
  267.         loadPalette(fp, &picture->pal); 
  268.     else
  269.         defaultPalette(&picture->pal);
  270.  
  271.     fclose(fp);
  272.     return picture;
  273. }
  274.  
  275. /*****************************************************************
  276. * FUNC: getBlock (unsigned char *byte, int *count, FILE *fp)
  277. * DESC: get a Run Length Encoded block.  It's either a byte or a
  278. *        string of bytes with a length given by count.
  279. *****************************************************************/
  280.  
  281. int
  282. getBlock (unsigned char *byte, int *count, FILE *fp)
  283. {
  284.     unsigned char input_byte;
  285.  
  286.     if (fread(&input_byte, sizeof(input_byte), 1, fp) != 1) 
  287.         return (EOF);
  288.     *count = 1;        /* so far */
  289.     if ((input_byte & C0) == C0) {
  290.         /* Top 2 bits on, data stream to follow */
  291.         /* mask out the byte count */
  292.         *count = input_byte & MAX_RUN;
  293.         mustRead(fp, &input_byte, 1);
  294.     }
  295.     *byte = input_byte;    /* return the byte */
  296.     return (0);        /* success */
  297. }
  298.  
  299. /*****************************************************************
  300. * FUNC: int    mustRead(FILE *fp, char *buf, int n)
  301. * DESC: Read bytes or quit.
  302. *****************************************************************/
  303.  
  304. int
  305. mustRead(FILE *fp, char *buf, int n)
  306. {
  307.     int nread;
  308.  
  309.     nread = fread(buf, sizeof(*buf), n, fp);
  310.     if (nread != n)
  311.         quit(READ_ERR, "");
  312. }
  313.     
  314. /*****************************************************************
  315. * FUNC: int    loadPalette(FILE *fp, PALETTE *palette)
  316. * DESC: Go to the end of the file and get the palette
  317. *****************************************************************/
  318.  
  319. loadPalette(FILE *fp, PALETTE *palette)
  320. {
  321.     unsigned char packed_pal[3*COLORS];
  322.     int        color, component;
  323.     int        red, green, blue;
  324.  
  325.     unsigned char input_byte;
  326.     fseek(fp, -(PALETTE_SIZE+1L), SEEK_END);    /* -1 on error */
  327.  
  328.     mustRead(fp, &input_byte, 1);
  329.     if (input_byte != PAL_CODE) {
  330.         printf("The color palette is missing!\n");
  331.         return (ERROR);
  332.     }
  333.     mustRead(fp, packed_pal, sizeof packed_pal);
  334.     for (component = 0, color = 0;
  335.             component < COMPS*COLORS; component += COMPS) {
  336.         palette->c[color].r = packed_pal[component+0]>>3;
  337.         palette->c[color].g = packed_pal[component+1]>>3;
  338.         palette->c[color].b = packed_pal[component+2]>>3;
  339.         color++;
  340.     }
  341.     palette->c[255].r = 0x1f;
  342.     palette->c[255].g = 0x1f;
  343.     palette->c[255].b = 0x1f;
  344.     return (0);
  345. }
  346.  
  347. /*****************************************************************
  348. * FUNC: int    freePicture(PICTURE *pic)
  349. * DESC: Free the memory allocated for this image.
  350. *****************************************************************/
  351.  
  352. int
  353. freePicture(PICTURE *pic)
  354. {
  355.     _ffree(pic->pixmap);
  356.     free(pic);
  357. }
  358.  
  359. /*****************************************************************
  360. * FUNC: LINE_LIST    *loadLines(char *filename, char *extension);
  361. * DESC: allocate and fill in LINE_LIST structure from file
  362. *****************************************************************/
  363.  
  364. LINE_LIST
  365. *loadLines(char *filename, char *extension)
  366. {
  367.     char        lineName[MAX_PATHLEN];
  368.     FILE        *fp;
  369.     char       *p;
  370.     LINE_LIST  *lineList;
  371.     int        number;
  372.     int        i;
  373.  
  374.     lineList = malloc(sizeof (*lineList));
  375.     lineList->number = 0;
  376.  
  377.     /* condition the filename to be a line list file name */
  378.     fixFilename(filename, lineName, extension, 0);
  379.     lineList->filename = strdup(lineName);
  380.  
  381.     fp = fopen(lineName, "r");
  382.     if (fp == NULL)
  383.         return lineList;
  384.  
  385.     if (fscanf(fp, "%d\n", &number) != 1
  386.                         || number < 1 || number > MAX_LINES) {
  387.         fclose(fp);
  388.         return lineList;
  389.     }
  390.  
  391.     lineList->number = number;
  392.     for(i=0;i<number;i++) {
  393.         if (fscanf(fp, "%d %d %d %d\n",
  394.                         &lineList->line[i].p[0].x,
  395.                         &lineList->line[i].p[0].y,
  396.                         &lineList->line[i].p[1].x,
  397.                         &lineList->line[i].p[1].y) != 4)
  398.             quit (READ_CONTENTS_ERR, lineName);
  399.         lineList->line[i].p[0].x = clip(lineList->line[i].p[0].x,
  400.                                         0, MAX_WIDE);
  401.         lineList->line[i].p[0].y = clip(lineList->line[i].p[0].y,
  402.                                         0, MAX_TALL);
  403.         lineList->line[i].p[1].x = clip(lineList->line[i].p[1].x,
  404.                                         0, MAX_WIDE);
  405.         lineList->line[i].p[1].y = clip(lineList->line[i].p[1].y,
  406.                                         0, MAX_TALL);
  407.         
  408.     }
  409.     fclose(fp);
  410.     return lineList;
  411. }
  412.  
  413. /*****************************************************************
  414. * FUNC: saveLines(char *filename, LINE_LIST *lineList,
  415. *                                                char *extension);
  416. * DESC: save lineList to a file
  417. *****************************************************************/
  418.  
  419. saveLines(char *filename, LINE_LIST *lineList, char *extension)
  420. {
  421.     /* big enough for number & '.PCX' */
  422.     char     lineName[MAX_PATHLEN];
  423.     FILE     *fp;
  424.     char    *p;
  425.     int     i;
  426.  
  427.     /* condition the filename to be a line list file name */
  428.     strcpy (lineName, filename);
  429.     strupr (lineName);
  430.     p= strstr(lineName, ".");
  431.     if (p == NULL)
  432.         p = lineName + strlen(lineName);
  433.     strcat(p, extension);        /* add extension, it's needed */
  434.  
  435.     fp = fopen(lineName, "w");
  436.     if (fp == NULL)
  437.         quit (WRITE_ERR, lineName);
  438.  
  439.     fprintf(fp, "%d\n", lineList->number);
  440.     for(i=0;i<lineList->number;i++) {
  441.         fprintf(fp, "%d %d %d %d\n",
  442.                     lineList->line[i].p[0].x,
  443.                     lineList->line[i].p[0].y,
  444.                     lineList->line[i].p[1].x,
  445.                     lineList->line[i].p[1].y);
  446.     }
  447.     fclose(fp);
  448. }
  449.  
  450. /*****************************************************************
  451. * FUNC: LINKED_LIST    *rootSequence(int argc, char *argv[])
  452. * DESC: Process argument list and return a sequence of pcx files
  453. *****************************************************************/
  454.  
  455. LINKED_LIST
  456. *rootSequence(int argc, char *argv[])
  457. {
  458.     LINKED_LIST *head = NULL;
  459.     int arg, loaded, i;
  460.     char filename[100];
  461.  
  462.     for (arg = 1; arg < argc; arg++) {
  463.         if (fixFilename(argv[arg], filename, EXT_PCX, 0))
  464.             head = appendName(head, filename);
  465.         else {
  466.             loaded = 0;
  467.             for(i=1;i<MAX_TWEENS;i++) {
  468.                 fixFilename(argv[arg], filename, EXT_PCX, i);
  469.                 if(_access(filename, 4) == 0) {
  470.                     head = appendName(head, filename);
  471.                     loaded = 1;
  472.                 }
  473.                 else if (loaded == 1)
  474.                     return head;  /* a break in the sequence */
  475.             }
  476.             /* didn't find a sequence, try using EXT_PCX */
  477.             fixFilename(argv[arg], filename, EXT_PCX, 0);
  478.             head = appendName(head, filename);
  479.         }
  480.     }
  481.     return head;
  482. }
  483.  
  484. /*****************************************************************
  485. * FUNC: LINKED_LIST    *appendName(LINKED_LIST *head, char *name)
  486. * DESC: add a data item to the end of the linked list
  487. *****************************************************************/
  488.  
  489. LINKED_LIST
  490. *appendName(LINKED_LIST *head, char *name)
  491. {
  492.     LINKED_LIST *l;
  493.     LINKED_LIST *end;
  494.  
  495.     l = (LINKED_LIST *) malloc(sizeof (LINKED_LIST));
  496.     l->str = strdup(name);
  497.      l->next = NULL;
  498.  
  499.     if (head == NULL)
  500.         return l;
  501.  
  502.     /* find guy that points to end */
  503.     for(end=head; end->next; end=end->next);
  504.     end->next = l;
  505.     return head;
  506. }
  507.  
  508. /*****************************************************************
  509. * FUNC: int fixFilename(char *userName, char *fixedName,
  510. *                                    char *extension, int number)
  511. * DESC: Create a valid filename with correct extension & number.
  512. *       Returns true if the userName had asn extension at end
  513. *****************************************************************/
  514.  
  515. int
  516. fixFilename(char *userName, char *fixedName, char *extension,
  517.                                                     int number)
  518. {
  519.     char *p;
  520.     char localbuf[100];
  521.     int  extensionFound;
  522.     
  523.     strcpy (localbuf, userName);
  524.     p = localbuf + strlen(localbuf) - 4;
  525.     /* extension is there */
  526.     extensionFound = strcmpi(p, extension) == 0;
  527.     if (extensionFound)
  528.         *p = '\0';
  529.     if (number)
  530.         sprintf(fixedName, "%s%d%s", localbuf, number, extension);
  531.     else
  532.         sprintf(fixedName, "%s%s", localbuf, extension);
  533.     return extensionFound;
  534. }
  535.  
  536. /***   These are the color and the screen handling routines   ***/
  537.  
  538. /*****************************************************************
  539. * FUNC: int    setPalette(PALETTE *palette)
  540. * DESC: Set the 256 colors in the palette, using the output ports
  541. *****************************************************************/
  542.  
  543. setPalette(PALETTE *palette)
  544. {
  545.     int        color;
  546.  
  547.     for (color = 0; color < COLORS; color++) {
  548.         _outp (0x3c7, color-1);
  549.         _outp (0x3c9, palette->c[color].r << 1);
  550.         _outp (0x3c9, palette->c[color].g << 1);
  551.         _outp (0x3c9, palette->c[color].b << 1);
  552.     }
  553. }
  554.  
  555. /*****************************************************************
  556. * FUNC: int    defaultPalette(PALETTE *palette)
  557. * DESC: Create a gray-scale palette as a default
  558. *****************************************************************/
  559.  
  560. defaultPalette(PALETTE *palette)
  561. {
  562.     int i;
  563.     long j;
  564.     long k;
  565.  
  566.     for (i=0;i<COLORS;i++) {
  567.         j = i & 0x1f;
  568.         palette->c[i].r = palette->c[i].g = palette->c[i].b = j;
  569.     }
  570. }
  571. /*****************************************************************
  572. * FUNC: int    displayPicture(PICTURE *picture)
  573. * DESC: set the video mode & palette, then draw from the buffer
  574. *        to the screen.
  575. *****************************************************************/
  576.  
  577. displayPicture(PICTURE *picture)
  578. {
  579.     int x, y, xb, yb;
  580.  
  581.     if (picture->pal_id == 0) {    /* need to define palette */
  582.         picture->pal_id = paletteID(&picture->pal);
  583.     }
  584.     if (CurrentPal != picture->pal_id) {
  585.         setPalette(&picture->pal);
  586.         CurrentPal = picture->pal_id;
  587.     }
  588.     displayNoPal(picture);    
  589. }
  590.  
  591. /*****************************************************************
  592. * FUNC: int    displayNoPal(PICTURE *picture)
  593. * DESC: display a picture without messing with the palette
  594. *****************************************************************/
  595.  
  596. int
  597. displayNoPal(PICTURE *picture)
  598. {
  599.     /* This is the memory address of the VGA screen */    
  600.     unsigned char far *screen = (unsigned char far *) 0xa0000000;
  601.     unsigned char far *bufptr = picture->pixmap;
  602.  
  603.     _fmemcpy (screen, bufptr, (unsigned int) MAX_BYTES);
  604.     wait(Wait);
  605. }
  606.  
  607. /*****************************************************************
  608. * FUNC: int    paletteID(PALETTE *pal)
  609. * DESC: return a unique id for each unique palette
  610. *****************************************************************/
  611.  
  612. int
  613. paletteID(PALETTE *pal)
  614. {
  615.     static PALETTE *definedPals[MAX_FILES];
  616.     static int npals = 0;
  617.     int i;
  618.  
  619.     for (i = 0; i < npals; i++) {
  620.         if (samePal(definedPals[i], pal))
  621.             return i+1;
  622.     }
  623.     definedPals[npals] = pal;
  624.     npals++;
  625.     return npals;
  626. }
  627.     
  628. /*****************************************************************
  629. * FUNC: int    samePal(PALETTE *p1, PALETTE *p2)
  630. * DESC: return 1 if same exact palettes, 0 otherwise
  631. *****************************************************************/
  632.  
  633. int
  634. samePal(PALETTE *p1, PALETTE *p2)
  635. {
  636.     int index;
  637.  
  638.     for (index = 0; index < COLORS; index++) {
  639.         if (p1->c[index].r != p2->c[index].r) return 0;
  640.         if (p1->c[index].g != p2->c[index].g) return 0;
  641.         if (p1->c[index].b != p2->c[index].b) return 0;
  642.     }
  643.     return 1;
  644. }
  645.  
  646. /*****************************************************************
  647. * FUNC: int    drawPalette()
  648. * DESC: Draw the 256 colors of the current palette in the top
  649. *        left of the screen.
  650. *****************************************************************/
  651.  
  652. int
  653. drawPalette()
  654. {
  655. #define BT 4    /* block tall */
  656. #define BW 6    /* block wide */
  657.  
  658.     int x, y, xb, yb;
  659.  
  660.     for (xb = 0; xb < 16; xb++) {
  661.         for (yb = 0; yb < 16; yb++) {
  662.             for (x = xb*BW; x < (xb*BW + BW); x++) {
  663.                 for (y = yb*BT; y < (yb*BT + BT); y++) {
  664.                     _setcolor(yb * 16 + xb);
  665.                     _setpixel (x, y);
  666.                     
  667.                 }
  668.             }
  669.         }
  670.     }
  671. }
  672.  
  673. /********************   The mouse routines   ********************/
  674.  
  675. /*****************************************************************
  676. * FUNC: int    initMouse()
  677. * DESC: Initialize the mouse and quit if a driver isn't present.
  678. *****************************************************************/
  679.  
  680. #define MOUSE 0x33
  681.  
  682. int
  683. initMouse()
  684. {
  685.     union _REGS regs;
  686.     struct _SREGS sregs;
  687.     regs.x.ax = 0x3533;
  688.     _intdosx(®s, ®s, &sregs);
  689.     if((regs.x.bx | sregs.es ) == 0)
  690.         quit(MOUSE_ERR, "");
  691.     regs.x.ax = 0;
  692.     _int86(MOUSE, ®s, ®s);
  693. }
  694.  
  695. /*****************************************************************
  696. * FUNC: int    hideMouse()
  697. * DESC: Hide the mouse cursor before we draw anything.
  698. *        This use the chunk of screen saved by showMouse.
  699. *****************************************************************/
  700.  
  701. int
  702. hideMouse()
  703. {
  704.     union _REGS regs;
  705.  
  706.     regs.x.ax = 0x02;
  707.     _int86(MOUSE, ®s, ®s);
  708. }
  709.  
  710. /*****************************************************************
  711. * FUNC: int    showMouse()
  712. * DESC: Redisplay the mouse cursor after drawing something on the
  713. *        screen. Save the chunk of screen under the cursor for
  714. *        hideMouse.
  715. *****************************************************************/
  716.  
  717. int
  718. showMouse()
  719. {
  720.     union _REGS regs;
  721.  
  722.     regs.x.ax = 0x01;
  723.     _int86(MOUSE, ®s, ®s);
  724. }
  725.  
  726. /*****************************************************************
  727. * FUNC: int    mousePos(int *x, int *y)
  728. * DESC: Return the x,y coordinates of the mouse and any
  729. *        button or keystroke.
  730. *****************************************************************/
  731.  
  732. #define KEYHIT    0x0b    /* Check the keyboard */
  733. #define STDIN     0x07      /* Read a char from standard input */
  734.  
  735. int
  736. mousePos(int *x, int *y)
  737. {
  738.     union _REGS regs;
  739.     char *buttons;
  740.     int keystroke;
  741.  
  742.     regs.h.ah = KEYHIT;
  743.     _intdos(®s, ®s);
  744.     keystroke = (regs.h.al == 0xff) ? KEYPRESS : 0;
  745.     if (keystroke) {
  746.         regs.h.ah = STDIN;
  747.         _intdos(®s, ®s);    /* STDIN */
  748.         if (Key = regs.h.al == ESC)
  749.             quit(0,"");            /* quit on Esc key */
  750.     }
  751.     regs.x.ax = 0x03;
  752.     _int86(MOUSE, ®s, ®s);
  753.     *x = regs.x.cx/2;            /* store the x & y coordinates */
  754.     *y = regs.x.dx;
  755.     /* return:    0 = none
  756.                    1 = left
  757.                    2 = right
  758.                 4 = keypress */
  759.     return (Button = (regs.x.bx & 0x03) | keystroke);
  760. }
  761.  
  762. /******************   A few utility routines   ******************/
  763.  
  764. /*****************************************************************
  765. * FUNC: int    waitForKey()
  766. * DESC: Wait for a key to be pressed, then return the key.
  767. *****************************************************************/
  768.  
  769. int
  770. waitForKey()
  771. {
  772.     int key;
  773.  
  774.     while (!_kbhit());
  775.     key = _getch();
  776.     if (key == ESC)
  777.         quit(0,"");
  778.     return (key); /* clear buffer and return keystroke */
  779. }
  780.  
  781. /*****************************************************************
  782. * FUNC: char    lineAsk(char *name)
  783. * DESC: Ask the users if they want to use the pre-defined lines.
  784. *****************************************************************/
  785.  
  786. char
  787. lineAsk(char *name)
  788. {
  789.     char c;
  790.  
  791.     setTextMode();
  792.  
  793.     _settextposition(VTAB, HTAB);
  794.     printf ("The picture '%s' has some pre-defined", name);
  795.     _settextposition(VTAB+2, HTAB);
  796.     printf ("control lines. Would you like to use them?");
  797.     _settextposition(VTAB+4, HTAB+8);
  798.     printf ("(Y/N):");
  799.     c = getche();
  800.     if (c == ESC)
  801.         quit(NO_ERROR, "");
  802.     c = toupper(c);
  803.     return c;
  804. }
  805.  
  806. /*****************************************************************
  807. * FUNC: int    quitCheck()
  808. * DESC: Check keyboard. If there is no key waiting, return 0,
  809. *        for OK. If a number from 1-9 is typed, change the wait
  810. *        between frames. Otherwise, the user wants to quit,
  811. *        so return 1.
  812. *****************************************************************/
  813.  
  814. int
  815. quitCheck()
  816. {
  817.     static int spaceWait = OFF;
  818.  
  819.     if (spaceWait) {
  820.         Key = getch();
  821.         if (Key != ' ')
  822.             spaceWait = OFF;
  823.     }
  824.     else if (_kbhit()) {
  825.         Key = _getch();
  826.         if (Key == ' ') {
  827.             /* turn on space bar stepping */
  828.             spaceWait = ON;
  829.             /* pause for space key */
  830.             Key = _getch();
  831.         }
  832.         if (Key == ESC || Key == 'q' || Key == 'Q')
  833.             return 1;                      /* a quit key */
  834.         if (Key == 'E' || Key == 'e')
  835.             EndWait ^= ON;                /* toggles on and off */
  836.         else if (Key >= '1' && Key <= '9')
  837.             Wait = '9' - Key;
  838.     }
  839.     return 0;
  840. }
  841.  
  842. /****************************************************************/
  843.  
  844. beep()
  845. {
  846.     printf("\a");
  847. }
  848.  
  849. /*****************************************************************
  850. * FUNC: int    clip(int num, int min, int max)
  851. * DESC: Clip the number to a value between min and max, inclusive.
  852. *****************************************************************/
  853.  
  854. int
  855. clip(int num, int min, int max)
  856. {
  857.     if (num < min)
  858.         num = min;
  859.     else if (num > max)
  860.         num = max;
  861.  
  862.     return num;
  863. }
  864.  
  865. /*****************************************************************
  866. * FUNC: int waitForTop() and waitForBottom()
  867. * DESC: These routines wait for the TV scan line to get to the
  868. *        top and the bottom of the screen.
  869. *****************************************************************/
  870.  
  871. #define VID_PORT 0x3da
  872. #define VID_RETRACE 0x8  
  873.  
  874. waitForTop()
  875. {
  876.     /* wait till retrace ends */
  877.     while(_inp(VID_PORT) & VID_RETRACE);
  878. }
  879. waitForBottom()
  880. {
  881.     /* wait till next retrace starts*/
  882.     while(!(_inp(VID_PORT) & VID_RETRACE));
  883. }
  884.  
  885. /*****************************************************************
  886. * FUNC: int    wait(int count)
  887. * DESC: Wait for a number of screen refreshes, based on count.
  888. *****************************************************************/
  889.  
  890. int
  891. wait (int count)
  892. {
  893.     int i;
  894.  
  895.     if (!count)
  896.         return 0;
  897.     for (i = 1; i < 2 * count; i++) {
  898.         waitForBottom();
  899.         waitForTop();
  900.     }
  901. }
  902.  
  903. /*****************************************************************
  904. * FUNC: void    setGraphicsMode()
  905. * DESC: Set up the graphics screen
  906. *****************************************************************/
  907.  
  908. void
  909. setGraphicsMode()
  910. {
  911.     _setvideomode(_MRES256COLOR);
  912.     CurrentPal = 0;                /* Force a new palette */
  913. }
  914.  
  915. /*****************************************************************
  916. * FUNC: void    setTextMode()
  917. * DESC: Set the screen to the startup text mode
  918. *****************************************************************/
  919.  
  920. void
  921. setTextMode()
  922. {
  923.     CurrentPal = 0;                /* Force a new palette */
  924.     _setvideomode(_DEFAULTMODE);
  925. }
  926.  
  927. /*****************************************************************
  928. * FUNC: void    quit(int err, char *name)
  929. * DESC: Turn text back on, print the error message and quit.
  930. *****************************************************************/
  931.  
  932. void
  933. quit(ERR err, char *name)
  934. {
  935.     static char *ErrMess[] = {
  936.         " ",
  937.         "I can't get enough memory. Try turning off some TSR's.",
  938.         "I can't find the file",
  939.         "I can't read the file",
  940.         "I can't open the file",
  941.         "I can't write the file",
  942.         "You must install a mouse driver to run this program.",
  943.         "This is the wrong PCX type - I can't read the file",
  944.     };
  945.     
  946.     setTextMode();
  947.     if (err != NO_ERROR) {
  948.         printf ("Error #%d:\n", err);
  949.         printf ("%s %s\n", ErrMess[err], name);
  950.         exit (err);
  951.     }
  952.     exit (0);
  953. }
  954.  
  955.  
  956.